from logging import getLogger

from zope.interface import Interface, implements
from zope.component import getSiteManager
from zope.configuration import config, fields
from zope.schema import TextLine, Object

from meercat.base.zcml import IRegistryItemSchema

from meercat.mapreduce.interfaces import IReducer 

from meercat.solr.mapreduce import interfaces
from meercat.solr.mapreduce.reducer import SolrReducer
from meercat.solr.mapreduce.processors import CopyField



log = getLogger('meercat.solr.zcml')

class ISolrReducerDirectiveSchema(Interface):
    name = TextLine(
        title=u'Name',
        description=u'A unique name for the reducer',
        required=True)
    
    formats = fields.Tokens(
        title=u'Formats',
        description=u'Formats reduced by this reducer',
        value_type=TextLine(),
        required=False,
        default=['solr'])
    
    defaultFieldReduction = fields.GlobalObject(
        title=u'Default Field Reduction',
        description=u'Default field reduction for fields that do not have a '
                    'specialized reducer',
        required=False,
        default=None,
        value_type=Object(schema=interfaces.ISolrFieldReducer))

class ISolrReducerDirective(ISolrReducerDirectiveSchema):
    def getPreprocessors(self):
        """ Return a registry of preprocessors that can be edited """
    
    def getPostprocessors(self):
        """ Return a registry of postprocessors that can be edited """

class ISolrProcessorDirective(IRegistryItemSchema):
    factory = fields.GlobalObject(
        title=u'Factory',
        description=u'The factory that creates the processor',
        required=False,
        default=None)

class ICopyFieldDirective(IRegistryItemSchema):
    source = TextLine(
        title=u'Source',
        description=u'The source field to copy from',
        required=True)
    
    destination = TextLine(
        title=u'Destination',
        description=u'The destination field to copy into',
        required=True)
    
    prefilter = fields.GlobalObject(
        title=u'Pre-Filter',
        description=u'Filter to apply before copying',
        required=False,
        default=None)
    
def solrProcessorHandler(context, name, factory=None, component=None, **kwargs):
    log.debug('solrProcessorHandler(%s,%s,%s,%s,**%s)' % (str(context),
                                                          str(name),
                                                          str(factory),
                                                          str(component),
                                                          str(kwargs)))
    if factory and component:
        raise ValueError("Can't specify factory and component.")
        
    if not (factory or component or name in context):
        raise TypeError('Either a component or a factory must be specified or '
                        'the processor must already be registered.')
    
    if factory:
        component = factory()
    
    if component and not interfaces.ISolrProcessor.providedBy(component):
        raise TypeError('The processor does not provide the ISolrProcessor '
                        'interface')
    
    return context.register(name, component, **kwargs)

def preprocessor(context, name, **kwargs):
    log.debug('preprocessor(%s, %s, **%s)' % (str(context), str(name), str(kwargs)))
    solrProcessorHandler(context.getPreprocessors(), name, **kwargs)

def postprocessor(context, name, **kwargs):
    log.debug('postprocessor(%s, %s, **%s)' % (str(context), str(name), str(kwargs)))
    solrProcessorHandler(context.getPostprocessors(), name, **kwargs)

def copyField(context, name, source, destination, prefilter=None, **kwargs):
    kwargs['component'] = CopyField(source, destination, prefilter)
    
    preprocessor(context, name, **kwargs)

class SolrReducerDirective(config.GroupingContextDecorator):
    implements(config.IConfigurationContext, ISolrReducerDirective)
    
    def __init__(self, context, name, formats=None, defaultFieldReduction=None):
        log.debug('%s.__init__(context=%s, name=%s, formats=%s, '
                  'defaultFieldReduction=%s)' % (str(self),str(context),
                                                 str(name),str(formats),
                                                 str(defaultFieldReduction),))
        self.context = context
        self.name = name
        self.formats = formats
        self.defaultFieldReduction=defaultFieldReduction
        self.reducer = None
    
    def before(self):
        log.debug('%s.before()' % (str(self),))
        super(SolrReducerDirective,self).before()
        
        manager = getSiteManager()
        
        self.reducer = manager.queryUtility(provided=IReducer, name=self.name)
        
        if self.reducer is None or not interfaces.ISolrReducer.providedBy(self.reducer):
            self.reducer = SolrReducer()
            manager.registerUtility(component=self.reducer,
                                    provided=IReducer,
                                    name=self.name)
        
        if self.formats is not None:
            self.reducer.formats = self.formats
        
        if self.defaultFieldReduction is not None:
            self.reducer.defaultFieldReduction = self.defaultFieldReduction
    
    def after(self):
        log.debug('%s.after()' % (str(self),))
        super(SolrReducerDirective,self).after()
    
    def getPostprocessors(self):
        log.debug('%s.getPostprocessors() = %s' % (str(self),
                                                   str(self.reducer.postprocessors)))
        return self.reducer.postprocessors
    
    def getPreprocessors(self):
        log.debug('%s.getPreprocessors() = %s' % (str(self),
                                                  str(self.reducer.preprocessors)))
        return self.reducer.preprocessors
